package com.sy.simpleegg.platform.kkb.network

import com.google.gson.Gson
import com.sy.simpleegg.platform.kkb.constant.Constant
import com.sy.simpleegg.platform.kkb.network.base.INetworkRequiredInfo
import com.sy.simpleegg.platform.kkb.network.config.Constants
import com.sy.simpleegg.platform.kkb.network.environment.IEnvironment
import com.sy.simpleegg.platform.kkb.network.errorhandler.HttpErrorHandler
import com.sy.simpleegg.platform.kkb.network.interceptor.RetryInterceptor
import com.sy.simpleegg.platform.kkb.network.interceptor.TimerResponseInterceptor
import io.reactivex.Observable
import io.reactivex.ObservableTransformer
import io.reactivex.Observer
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.functions.Function
import io.reactivex.schedulers.Schedulers
import okhttp3.Interceptor
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
import retrofit2.converter.gson.GsonConverterFactory
import java.util.concurrent.TimeUnit

/**
 * @author sy
 * @date 2024/10/11 14:56
 * @desc
 */
abstract class NetWorkApi: IEnvironment {
    private var iNetworkRequiredInfo: INetworkRequiredInfo? = null
    var mBaseUrl = ""
    private var mOkHttpClient: OkHttpClient? = null
    private var retrofitHashMap: HashMap<String?, Retrofit?> = HashMap<String?, Retrofit?>()

    init {
//        if (iNetworkRequiredInfo!!.isDebug()) {
//            mBaseUrl = this.getTestUrl()!!
//        } else {
//            mBaseUrl = this.getFormalUrl()!!
//        }

        mBaseUrl = if (Constant.IS_TEST) Constants.BASE_BUSINESS_URL_TEST else Constants.BASE_BUSINESS_URL_PRO
    }

    open fun init(networkRequiredInfo: INetworkRequiredInfo?) {
        iNetworkRequiredInfo = networkRequiredInfo
    }

    open fun cleanCash() {
        retrofitHashMap.clear()
        retrofitHashMap = HashMap<String?, Retrofit?>()
    }

    open fun <T> getRetrofit(serviceClass: Class<T>): Retrofit {
        return if (retrofitHashMap!![mBaseUrl + serviceClass.name] != null) {
            retrofitHashMap!![mBaseUrl + serviceClass.name] as Retrofit
        } else {
            val builder = Retrofit.Builder()
            builder.baseUrl(mBaseUrl)
            builder.client(getOkHttpClient())
            builder.addConverterFactory(GsonConverterFactory.create(Gson()))
            builder.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
            val retrofit = builder.build()
            retrofitHashMap!![mBaseUrl + serviceClass.name] = retrofit
            retrofit
        }
    }

    private fun getOkHttpClient(): OkHttpClient? {
        if (mOkHttpClient == null) {
            val okHttpClientBuilder = OkHttpClient.Builder()
            val interceptors = interceptorList()
            if (interceptors != null) {
                val var3: Iterator<*> = interceptors.iterator()
                while (var3.hasNext()) {
                    val interceptor = var3.next() as Interceptor
                    okHttpClientBuilder.addInterceptor(interceptor)
                }
            }
            okHttpClientBuilder.addInterceptor(TimerResponseInterceptor())
            if (getRetryCount() > 0) {
                okHttpClientBuilder.retryOnConnectionFailure(true)
                okHttpClientBuilder.addInterceptor(
                    RetryInterceptor(
                        getRetryCount()
                    )
                )
            }
            if (iNetworkRequiredInfo != null && iNetworkRequiredInfo!!.isDebug()) {
                okHttpClientBuilder.connectTimeout(
                    iNetworkRequiredInfo!!.getTimeOut().toLong(),
                    TimeUnit.SECONDS
                )
                okHttpClientBuilder.readTimeout(
                    iNetworkRequiredInfo!!.getTimeOut().toLong(),
                    TimeUnit.SECONDS
                )
                val httpLoggingInterceptor = HttpLoggingInterceptor()
                httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY)
                okHttpClientBuilder.addInterceptor(httpLoggingInterceptor)
            }
            mOkHttpClient = okHttpClientBuilder.build()
        }
        return mOkHttpClient
    }

    open fun <T> applySchedulers(observer: Observer<T>?): ObservableTransformer<T?, T?>? {
        return ObservableTransformer { upstream: Observable<T> ->
            val observable: Observable<T> =
                upstream.subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread()).map(getAppErrorHandler())
                    .onErrorResumeNext(HttpErrorHandler())
            observable.subscribe(observer!!)
            observable
        }
    }

    abstract fun <T> getAppErrorHandler(): Function<T, T>?

    abstract fun interceptorList(): List<Interceptor>?

    abstract fun getRetryCount(): Int

    abstract fun <T> getService(service: Class<T>): T
}